<?php
/**
 * Created by PhpStorm.
 * User: Mysic
 * Date: 2020/10/21
 * Time: 16:43
 */

namespace app\api\controller;

use app\common\mysic\WxRefundErrorResponseHandle;
use think\Controller;
use Throwable;
use org\RabbitMQ;
use think\Db;
use think\Env;
use think\Request;
use utils\Services;
use app\factory\MqFactory;
use app\mocks\extend\MockWeChatPay;
use app\mocks\extend\MockWeChatProfitSharing;
use app\common\model\divide\Receive;
use app\common\model\divide\ReceiveUser;
use app\common\model\divide\Refund;
use app\common\model\divide\Service;
use app\common\model\divide\System;
use app\common\model\divide\Store;
use app\common\model\VipCardOrder;
use app\common\model\dealer\Capital;
use app\common\model\Wxapp as WxappModel;
use app\common\model\Order;
use app\common\model\User;
use app\common\model\Wxsetting;
use app\common\model\Agent;
use app\common\model\dealer\User as DealUser;
use app\common\mysic\bonus\BonusHandler;
use app\common\mysic\bonus\BonusReceiveOp;
use app\common\mysic\bonus\BonusReceiveUserOp;
use app\common\library\wechat\Abonus;
use app\common\library\wechat\WxPay;
use app\common\library\MysicLog;
use app\common\mysic\bonus\BonusRefundOp;
use app\common\mysic\order\UserOrderOp;
use app\common\mysic\order\VipCardHandler;
use app\common\mysic\user\DealUserAccountOp;
use app\common\mysic\user\UserAccountOp;
use app\common\mysic\order\AgentDividendOrderOp;
use app\common\mysic\order\StoreDividendOrderOp;
use app\common\mysic\dividend\AgentDividendHandler;
use app\common\mysic\dividend\StoreDividendHandler;
use app\common\mysic\dividend\SystemDividendHandler;
use app\common\mysic\order\SystemDividendOrderOp;




class Bonus extends Controller
{
    /**
     * @var MysicLog|null 自定义log
     */
    protected $log;
    /**
     * @var $rmq RabbitMQ 句柄
     */
    protected $rmq;
    /**
     * @var SystemDividendHandler 平台分账处理器
     */
    protected $systemDividendHandler;
    /**
     * @var AgentDividendHandler 代理商分账处理器
     */
    protected $agentDividendHandler;
    /**
     * @var StoreDividendHandler 商户分账处理器
     */
    protected $storeDividendHandler;
    /**
     * @var BonusHandler 用户分红（退款）处理器
     */
    protected $bonusHandler;
    /**
     * @var User 用户模型
     */
    protected $userModel;
    /**
     * @var Agent 代理商模型
     */
    protected $agentModel;
    /**
     * @var System 平台分账订单模型
     */
    protected $divideSystemModel;
    /**
     * @var Service 代理商分账订单模型
     */
    protected $divideAgentModel;
    /**
     * @var Store 商户分账订单模型
     */
    protected $divideStoreModel;
    /**
     * @var Wxsetting 商户分红设置模型
     */
    protected $bonusSettingModel;
    /**
     * @var Order 用户订单模型
     */
    protected $userOrderModel;
    /**
     * @var WxappModel 微信小程序模型
     */
    protected $miniProgramModel;
    /**
     * @var SystemDividendOrderOp 平台分账订单模型操作器
     */
    protected $systemDividendOrderOp;
    /**
     * @var AgentDividendOrderOp 代理商分账订单模型操作器
     */
    protected $agentDividendOrderOp;
    /**
     * @var StoreDividendOrderOp 商户分账订单模型操作器
     */
    protected $storeDividendOrderOp;
    /**
     * @var Abonus 原支付分账类
     */
    protected $dividendBonusApi;
    /**
     * @var BonusReceiveOp 用户分红记录操作器
     */
    protected $bonusReceiveOp;
    /**
     * @var Receive
     */
    protected $bonusReceiveModel;
    /**
     * @var ReceiveUser
     */
    protected $bonusReceiveUserModel;
    /**
     * @var WxPay
     */
    protected $wxPayApi;
    /**
     * @var BonusReceiveUserOp
     */
    protected $bonusReceiveUserOp;
    /**
     * @var Refund
     */
    protected $bonusRefundModel;
    /**
     * @var BonusRefundOp
     */
    protected $bonusRefundOp;
    /**
     * @var VipCardOrder
     */
    protected $cardOrderModel;
    /**
     * @var VipCardHandler
     */
    protected $cardOrderHandler;
    /**
     * @var DealUserAccountOp
     */
    protected $dealUserAccountOp;
    /**
     * @var UserAccountOp
     */
    protected $userAccountOp;
    /**
     * @var Capital
     */
    protected $dealUserCapitalModel;
    /**
     * @var DealUser
     */
    protected $dealUserModel;
    /**
     * @var UserOrderOp
     */
    protected $userOrderOp;

    public function __construct(Request $request = null)
    {
        parent::__construct($request);
        $this->rmq = MqFactory::instance();
        $this->log = MysicLog::instance();
    }


    public function dividend()
    {
        $this->log->setFilename('weigudong/dividend');
        try {
            $this->dividendConsumerInit();
            $processMessage = function ($envelope) {
                $json = $envelope->getBody();
                $msg  = json_decode($json);
                //获取用户支付的订单信息
                try {
                    $this->log->info('', '-----------------------------------------------------------------');
                    $this->log->info($json, '分账开始 - 队列消息内容');
                    $this->log->info('开始', '获取用户支付的订单信息');
                    $userOrderEntity = $this->userOrderModel->where('order_id', $msg->orderId)->find();
                    $this->log->info(json_encode($userOrderEntity->toArray(), JSON_UNESCAPED_UNICODE), '用户支付订单信息');
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '获取商品订单实体抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                //获取商户的分红设置
                try {
                    $this->log->info('开始', '获取商户的分红设置');
                    $bonusSettingEntity = $this->bonusSettingModel->where('wxapp_id', $userOrderEntity->wxapp_id)->find();
                    if(!$bonusSettingEntity) {
                        $this->log->error('分红设置为空','获取商户的分红设置结果');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                    $this->log->info(json_encode($bonusSettingEntity->toArray(), JSON_UNESCAPED_UNICODE), '商户分红设置');
                    $issue = $bonusSettingEntity->periods_num ?? 0;
                    $this->log->info($issue, '分红期号');
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '获取商户分红设置抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                //初始化此订单支付人是否加入分红队列并更新微股东身份
                $joinShareHolder = true;
                //初始化此订单是否给其他用户分红
                $bonusAble = true;
                //初始化此订单是否给自己分红
                $selfBonusAble = true;
                //初始化是否分账
                $dividendAble = true;
                // 初始化分红上限金额 本次分红平均金额 本次分红总金额
                $bonusUpperLimit = 0;
                $bonus = 0;
                $totalBonus = 0;
                //根据订单号获取储值卡信息
                try {
                    $this->log->info('开始', '根据订单号获取储值卡信息');
                    //判断订单是否是储值卡订单
                    if ($userOrderEntity->order_source == 40) {//无此字段
                        $this->log->info('true', '判断支付订单是否是储值卡');
                        $this->cardOrderHandler->setModel($this->cardOrderModel)->setUserOrder($userOrderEntity)->instanceCardEntity();

                        $this->log->info('开始', '将商户分红拨比更改为储值卡设置的分红拨比');
                        //储值卡分红上限不为0时，将商户分红拨比更改为储值卡设置的分红拨比
                        $this->log->info($bonusSettingEntity->rewardpercent, '商户分红拨比');
                        $this->log->info($this->cardOrderHandler->getBonusRate(), '储值卡分红拨比');
                        if($this->cardOrderHandler->getBonusRate() > 0) {
                            $bonusSettingEntity->rewardpercent = $this->cardOrderHandler->getBonusRate();
                        }
                        $this->log->info($this->cardOrderHandler->getBonusRate(), '储值卡分红上限');
                    }
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '储值卡分红上限替换商户分红上限时抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                //获取分红用户总人数
                $userReceives   = $this->bonusReceiveModel
                    ->where(['wxapp_id' => $userOrderEntity->wxapp_id, 'type' => 0, 'periods_num' => $bonusSettingEntity->periods_num])
                    ->whereTime('finish_time', '>', time())

                    ->field('receives_id,type,order_no, times,balance,wxapp_id,payment,periods_num,user_id,account,top_limit,transaction_id,is_large')
                    ->order('create_time desc')
                    ->select()->toArray();
                $bonusUserCount = count($userReceives);
                $this->log->info($bonusUserCount + 1, '参与分红用户总人数');
                // 本期活动分红队列为空，不给其他用户分
                if($bonusUserCount < 1 || $bonusSettingEntity->start_time > $msg->time) {
                    $this->log->info('', '本期活动分红队列为空，不给其他用户分');
                    $bonusAble = false;
                }
                //活动设置不存在 |  活动未开始 | 活动已关闭 | 商品不是虚拟商品 | 订单金额未达到参与活动最低金额， 本订单用户身份不更新为微股东,不分红
                if(!$bonusSettingEntity || $bonusSettingEntity->start_time > $msg->time || $bonusSettingEntity->status != 1 || $userOrderEntity->pay_price < $bonusSettingEntity->money)
                {
                    $log = [
                        '活动设置是否存在' => bool2str(isset($bonusSettingEntity)),
                        '活动未开始' => bool2str($bonusSettingEntity->start_time > $msg->time),
                        '活动已关闭' => bool2str($bonusSettingEntity->status != 1),
//                        '商品不是虚拟商品' => bool2str($userOrderEntity->is_fictitious != 1),
                        '订单金额未达到参与活动最低金额' => bool2str($userOrderEntity->pay_price < $bonusSettingEntity->money)
                    ];
                    $this->log->info($log, '条件判断结果');
                    $log = [
                        '用户不更新为微股东' => true,
                        '不给用户分红' => true
                    ];
                    $this->log->info($log, '条件判断结果');
                    $joinShareHolder = false;
                    $selfBonusAble = false;
                }
                //计算本次分红的分红上限 分红金额
                if($bonusSettingEntity && ($bonusAble || $selfBonusAble)) {
                    if(!$selfBonusAble) {
                        $bonusUserCount--;
                    }
                    $bonusUpperLimit = bcmul(strval($userOrderEntity->pay_price), bcdiv(strval($bonusSettingEntity->upline), '100',2),2);
                    $bonus = $this->bonusHandler
                        ->setBonusSetting($bonusSettingEntity)
                        ->setUserOrder($userOrderEntity)
                        ->calculateBonus($bonusUserCount)
                        ->getBonus();
                    $this->log->info($bonus, '计算出的分红金额');
                    $totalBonus = $this->bonusHandler->getTotalBonus();
                }
                // 分红金额小于1分钱 ,所有用户不分红
                if($bonus <= 0) {
                    $this->log->info('', '分红金额小于1分钱 ,所有用户不分红');
                    $bonusAble = false;
                    $selfBonusAble = false;
                }
                //商品为实物商品
                if($userOrderEntity->is_fictitious != 1 && $bonusSettingEntity->real_reward == 0) {
                    $dividendAble = false;
                    $bonusAble = false;
                    $selfBonusAble = false;
                    $joinShareHolder = false;
                }

                //平台、代理分账不分账，申请订单完结分账 [流程结束]
                if(!$dividendAble) {
                    $this->log->info('开始',  '实物商品，不作分账，完结分账订单');
                    try {
                        $ret = $this->systemDividendHandler->setDividendApi($this->dividendBonusApi)->dividendOver('实物商品，不作分账，完结分账订单');
                    } catch(Throwable $e) {
                        $this->log->error(exceptionLogFormat($e), '实物商品，不作分账，完结分账订单时抛出异常');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                    if(!$ret) {
                        $this->log->info('失败',  '实物商品，不作分账，完结分账订单');
                    } else {
                        $this->log->info('完成',  '实物商品，不作分账，完结分账订单');
                    }
                    $this->log->info('', '业务结束');
                    return true;
                }
                //用户成为微股东，加入分红队列
                if ($joinShareHolder) {
                    $this->log->info('执行', '用户成为微股东，加入分红队列');
                    try {
                        $this->log->info('开始', '更新用户为微股东');
                        $userEntity = $this->userModel->where('user_id', $userOrderEntity->user_id)->find();
                        if ($userEntity->shareholder == 0) {
                            $this->log->info('不是，将用户更新为微股东', '判断用户是否已是微股东身份');
                            $userEntity->shareholder = 1;
                            $ret = $userEntity->save();
                            if (!$ret) {
                                $this->log->error('失败', '用户更新成微股东');
                            }
                        }
                        $this->log->info('结束', '用户更新成微股东');
                    } catch (Throwable $e) {
                        $this->log->error(exceptionLogFormat($e), '用户身份更新为微股东时抛出异常');
                        $this->log->info('', '业务结束');
                        return true;
                    }

                    //添加用户到分红队列主表
                    $this->log->info('开始', '添加用户到分红用户主表');
                    try {
                        $ret = $this->bonusReceiveOp
                            ->setBonusSetting($bonusSettingEntity)
                            ->setUserOrder($userOrderEntity)
                            ->setUserModel($this->userModel)
                            ->setModel($this->bonusReceiveModel)
                            ->setUpperLimit($bonusUpperLimit)
                            ->setBonus(0)
                            ->create();
                        if (!$ret) {
                            $this->log->error('失败', '添加用户到分红用户主表');
                        }
                        $this->log->info('成功', '添加用户到分红用户主表');
                    } catch (Throwable $e) {
                        $this->log->error(exceptionLogFormat($e), '添加用户到分红用户主表时抛出异常');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                    $this->log->info('结束', '添加用户到分红用户主表');
                }
                //给用户本次订单分红
                if($selfBonusAble) {
                    $this->log->info('开始', '给用户本次订单分红');
                    try {
                        //获取微信接口配置
                        $wxConfig = WxappModel::getWxappRedis($userOrderEntity->wxapp_id);
                        $this->log->info(json_encode($wxConfig,JSON_UNESCAPED_UNICODE), '获取微信接口配置');
                    } catch (Throwable $e) {
                        $this->log->error(exceptionLogFormat($e), '支付人退款 - 获取微信小程序配置信息抛出异常');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                    //发起微信退款申请
                    try {
                        $this->log->info('开始', '给当前订单的用户分红-发起微信退款申请');
                        //设置微信退款接口config参数
                        $this->wxPayApi->setConfigArr($wxConfig);

                        // 分红上限小于分红金额， 按上限金额分红
                        if(($bonusUpperLimit - $bonus) < 0) {
                            $this->bonusHandler->setBonus($bonusUpperLimit);
                        }
                        $ret = $this->bonusHandler->setApi($this->wxPayApi)->run();
                    } catch (Throwable $e) {
                        $this->log->error(exceptionLogFormat($e), '支付人退款申请抛出异常');
                        $this->log->info('', '业务结束');
                        $ret = false;
                    }
                    if ($ret) {
                        $this->log->info('开始', '分红成功，更新主表累计分红数据');
                        $this->bonusReceiveOp
                            ->setUserModel($this->userModel)
                            ->setReceiveEntity($this->bonusReceiveOp->getReceiveEntity())
                            ->setBonus($bonus)
                            ->update($this->bonusReceiveOp::NOT_FINISHED, $this->bonusReceiveOp::BONUS_REFUND);
                        //微信退款申请成功
                        $this->log->info('', '微信退款申请成功');
                        //添加用户本次分红到分红用户记录副表中
                        try {
                            $this->log->info('开始', '添加用户本次分红到分红用户记录副表');
                            $this->bonusReceiveUserOp
                                ->setModel($this->bonusReceiveUserModel)
                                ->setBonusSetting($bonusSettingEntity)
                                ->setReceiveEntity($this->bonusReceiveOp->getReceiveEntity())
                                ->setRefundData($this->bonusHandler->getWxRefundData())
                                ->setRefundType(1)
                                ->setBonus($this->bonusHandler->getBonus())
                                ->create();
                        } catch (Throwable $e) {
                            $this->log->error(exceptionLogFormat($e), '设置Operator参数时抛出异常');
                            $this->log->info('', '业务结束');
                            return true;
                        }
                    } else {
                        //微信退款申请失败
                        $this->log->info('失败', '微信退款申请');
                        //写入退款失败记录表
                        $this->log->info('开始', '写入退款失败记录表');
                        try {

                            $ret = $this->bonusRefundOp
                                ->setModel($this->bonusRefundModel)
                                ->setBonusSettingEntity($bonusSettingEntity)
                                ->setUserModel($this->userModel)
                                ->setUserOrder($userOrderEntity)
                                ->setBonus($this->bonusHandler->getBonus())
                                ->setWxRefundResponse($this->bonusHandler->getWxRefundData() ?? [])
                                ->create();
                            if (!$ret) {
                                $this->log->error('失败', '添加分红失败到支付人分红退款失败表');
                            }
                            $this->log->info('', '业务结束');
                            return true;
                        } catch (Throwable $e) {
                            $this->log->error(exceptionLogFormat($e), '支付人退款申请失败写入退款失败表时抛出异常');
                            $this->log->info('', '业务结束');
                            return true;
                        }
                    }
                    if(($bonusUpperLimit - $bonus) <= 0) {
                        $this->log->info('开始', '分红上限小于或等于本次分红金额，更新此订单为出局');
                        try {
                            $this->bonusReceiveOp
                                ->setUserModel($this->userModel)
                                ->setReceiveEntity($this->bonusReceiveOp->getReceiveEntity())
                                ->setBonus(0)
                                ->update($this->bonusReceiveOp::FINISHED, $this->bonusReceiveOp::BONUS_REFUND);
                            $this->log->info('结束', '分红上限小于或等于本次分红金额，更新此订单为出局');
                        } catch (Throwable $e) {
                            $this->log->error(exceptionLogFormat($e), '更新此订单为出局时抛出异常');

                        }
                    }
                }
                $agentId = $this->miniProgramModel->where(['wxapp_id' => $userOrderEntity->wxapp_id])->value('agent_id');
                //创建服务商分账流水
                try {
                    $this->log->info('开始', '创建服务商分账订单');
                    $this->agentDividendOrderOp->setModel($this->divideAgentModel)->setOrder($userOrderEntity);

                    // 目前是查全表数据，需要优化成根据agent_id做条件查询
                    $allAgent = $this->agentModel->where([
                        'is_recycle' => 0,
                        'status'     => 1,
                        'is_delete'  => 0
                    ])->order('agent_id desc')->select()->toArray();

                    if (!empty($agentId) && !empty($allAgent)) {
                        $tree = Services::instance();
                        $tree->init($allAgent, 'recommend_id');
                        $thisAgentInfo=Db::name('agent')->where(['agent_id'=>$agentId])->value('type');
                        if($thisAgentInfo==3){
                            $agentList = $tree->getParents($agentId, false);
                        }else{
                            $agentList = $tree->getParents($agentId, true);
                        }
                        $ret       = $this->agentDividendOrderOp->setAgents($agentList)->setIssue($issue)->create();

                        $this->log->info(['代理商个数' => count($agentList), '成功创建订单数' => $ret], '代理商分账订单入库结果');
                        if (!$ret || count($agentList) != $ret) {
                            $this->log->error('失败量：'.(count($agentList) - $ret), '代理商分账订单入库数据存在失败');
                        }
                    }
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '创建代理商分账订单抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                //创建平台分账订单
                try {
                    $this->log->info('开始', '创建平台分账订单');
                    $agentEntity = $this->agentModel->where('agent_id', $agentId)->find();
                    $this->log->info($agentEntity ? $agentEntity->toArray() : [], '代理商信息');
                    $ret = $this->systemDividendOrderOp
                        ->setIssue($issue)
                        ->setModel($this->divideSystemModel)
                        ->setAgentsAmount($this->agentDividendOrderOp->getAgentsAmount())
                        ->setOrder($userOrderEntity)
                        ->create();
                    if (!$ret) {
                        $this->log->error('失败', '创建平台分账订单');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '创建平台分账订单抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }

                //创建商家分账订单
                try {
                    $this->log->info('开始', '创建商家分账订单');
                    $miniProgramEntity = $this->miniProgramModel->where(['wxapp_id' => $userOrderEntity->wxapp_id])->find();
                    $this->log->info(json_encode($miniProgramEntity->toArray(), JSON_UNESCAPED_UNICODE), '获取微信小程序信息');
                    $ret =  $this->storeDividendOrderOp
                        ->setModel($this->divideStoreModel)
                        ->setOrder($userOrderEntity)
                        ->setBonus($totalBonus)
                        ->setMiniProgramEntity($miniProgramEntity)
                        ->setBonusSettingEntity($bonusSettingEntity)
                        ->setIssue($issue)
                        ->create();

                    if (!$ret) {
                        $this->log->error('失败', '创建商家分账订单');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '创建商户分账订单抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                //调用微信分账申请接口
                try {
                    $this->log->info('开始', '调用微信分账申请接口');
                    $ret = $this->systemDividendHandler->setDividendApi($this->dividendBonusApi)->setOp($this->systemDividendOrderOp)->doDividend();
                    if(!$ret) {
                        $this->log->info('', '业务结束');//doDividend方法中已记录失败原因
                        return true;
                    }
                } catch (Throwable $e) {
                    $error = $e->getMessage();
                    //分账申请失败
                    $this->systemDividendOrderOp->failure($error);
                    $this->agentDividendOrderOp->failure($error);
                    $this->storeDividendOrderOp->failure($error);
                    $this->log->error(exceptionLogFormat($e), '分账申请流程抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                $this->log->info('成功', '分账申请流程');
                //分账申请成功
                try {
                    $this->log->info('开始', '更新平台、代理商、商户分账订单');
                    $this->systemDividendOrderOp->success();
                    $this->agentDividendOrderOp->success();
                    $this->storeDividendOrderOp->success();
                    $this->userOrderOp->setEntity($userOrderEntity)->success();
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '更新平台、代理商、商户分账订单抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                $this->log->info('成功', '更新平台、代理商、商户分账订单');

                if ($bonusAble) {
                    $this->log->info('开始', '其他用户分红');
                    $this->log->info($this->bonusHandler->getBonus() * 100, '分红金额');
                    $this->log->info('是', '判断其他用户是否分红');
                    $this->log->info('开始', '其他用户分红写入消息队列');
                    $largeReceives = $msgList = [];
                    foreach ($userReceives as $receive) {
                        if($receive['is_large'] == 1){
                            $msgList[] = $rmqMsg = [
                                'receives_id'    => $receive[ 'receives_id' ],
                                'bonus'          => $this->bonusHandler->getBonus(),
                                'reward_percent' => $bonusSettingEntity->rewardpercent,
                                'order_id' =>  $msg->orderId
                            ];
                            $this->rmq->send($rmqMsg, 'merchant', 'bonus', 'bonus');
                        }
                        if($receive['is_large'] == 2){
                            $largeReceives[] = [
                                'receives_id' => $receive[ 'receives_id' ],
                                'order_id' => $msg->orderId,
                                'bonus' => $this->bonusHandler->getBonus()
                            ];
                        }
//                            $wxMerchantId = $this->miniProgramModel->where(['wxapp_id' => $userOrderEntity->wxapp_id])->value('mchid');//todo 按商户mchid号，入列
                    }
                    $this->log->info(json_encode($msgList, JSON_UNESCAPED_UNICODE), '小额-写入队列的消息');
                    $this->log->info(json_encode($largeReceives, JSON_UNESCAPED_UNICODE), '大额-写入队列的消息');
                    if($largeReceives) {
                        foreach($largeReceives as $largeMsg) {
                            $this->rmq->send($largeMsg, 'largeDivide', 'largeDivideLog', 'largeDivideLog');
                        }
                    }

                    $this->log->info('结束', '其他用户分红写入消息队列');
                }else {
                    $this->log->info('否', '判断其他用户是否分红');
                }
                $this->log->info('', '业务结束');
                return true;
            };
        } catch (Throwable $e) {

            $this->log->error(exceptionLogFormat($e), '分账队列消费抛出异常');
        }
        $this->rmq->run($processMessage, 'userListData', 'userListDataLog', 'userListDataLog');
        return true;
    }

    public function bonus()
    {
        $this->log->setFilename('weigudong/bonus');
        $this->bonusConsumerInit();
        $processMessage = function ($envelope) {
            try {
                $xml = $envelope->getBody();
                $msg = json_decode($xml, true);
                $this->log->info('', '-----------------------------------------------------------------');
                $this->log->info($msg, '用户分红开始 - 队列消息内容');
                $bonus = $msg[ 'bonus' ];
                // 获取用户订单
                $paidUserOrderEntity = $this->userOrderModel->where('order_id', $msg['order_id'])->find();
                $this->log->info(json_encode($paidUserOrderEntity->toArray() ?? [], JSON_UNESCAPED_UNICODE), '获取当次分红的发起订单');
                // 获取本次用户分红主表信息
                try {
                    $receivesEntity = $this->bonusReceiveModel->where('receives_id', $msg[ 'receives_id' ])->find();
                    $this->log->info(json_encode($receivesEntity->toArray() ?? [], JSON_UNESCAPED_UNICODE), '获取用户分红记录');
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '获取用户分红信息时抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                // 获取用户订单信息
                try {
                    $userOrderEntity = $this->userOrderModel->where('order_no', $receivesEntity->order_no)->find();
                    $this->log->info(json_encode($userOrderEntity->toArray(), JSON_UNESCAPED_UNICODE), '获取该分红用户的分红订单');
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '获取用户订单信息抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                // 获取用户信息
                try {
                    $userEntity = $this->userModel->where([
                        'user_id'  => $userOrderEntity->user_id,
                        'wxapp_id' => $userOrderEntity->wxapp_id
                    ])->find();
                    $this->log->info(json_encode($userEntity->toArray(), JSON_UNESCAPED_UNICODE), '获取用户信息');
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '获取用户信息时抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                //获取分红设置
                try {
                    $bonusSettingEntity = $this->bonusSettingModel->where('wxapp_id', $userOrderEntity->wxapp_id)->find();
                    $this->log->info(json_encode($bonusSettingEntity->toArray(),JSON_UNESCAPED_UNICODE), '获取商户分红设置');
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '获取商户分账设置信息时抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                //分红余额小于分红金额时，分红金额与余额的差额账面上要返还给商户
                if($receivesEntity->balance < $bonus) {
                    $this->log->info('开始','分红余额小于分红金额，差额返还给商户');
                    $remainder = $bonus - $receivesEntity->balance;
                    $bonus = $receivesEntity->balance;
                    try{
                        $dividendStoreEntity = $this->divideStoreModel->where('order_no', $userOrderEntity->order_no)->find();
                        $this->storeDividendOrderOp
                            ->setModel($dividendStoreEntity)
                            ->setOrder($paidUserOrderEntity)
                            ->updateAmount(['amount' => Db::raw('amount-' .$remainder)]);
                    }catch(\Throwable $e){
                        $this->log->error(exceptionLogFormat($e), '更新商户分账流水金额时抛出异常');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                }
                $bonusType = 0;
                if($bonus > 0) {
                    // 根据消息传递的分红拨比，更新分红设置拨比
                    $bonusSettingEntity->rewardpercent != $msg[ 'reward_percent' ] && $bonusSettingEntity->rewardpercent = $msg[ 'reward_percent' ];
                    $this->log->info($msg[ 'reward_percent' ], '队列传递的分红拨比');
                    $this->log->info($bonusSettingEntity->rewardpercent, '更改后的分红拨比');
                    $this->log->info($bonus, '分红金额');
                    $this->log->info($receivesEntity->balance, '用户分红余额');
                    $this->log->info($receivesEntity->times, '用户已分红次数');
                    $this->log->info(bool2str($receivesEntity->finish_time <= time()), '该用户的分红活动是否过期');
                    // 用户订单分红已到期，分红余额转零钱
                    if($receivesEntity->finish_time <= time()) {
                        if($bonusSettingEntity->moneypercentstatus == 1) {
                            $this->log->info('分红余额转到零钱','用户订单分红已到期');
                            $bonusType = $this->bonusReceiveOp::BONUS_BALANCE;
                            //余额转零钱
                            $balance = bcadd($userEntity->balance, $receivesEntity->balance,2);
                            $bonus = $receivesEntity->balance;
                            $ret = $this->userAccountOp->setUserEntity($userEntity)->setOrderEntity($userOrderEntity)->upgradeBalance($balance, $receivesEntity->balance);
                        } else {
                            $this->log->info('分红余额不转零钱','商户零钱开关设置为关闭');
                            $bonus = 0;
                            $ret = true;
                        }
                    }
                    // 用户订单分红次数达到46次， 分红金额分到赏金中
                    elseif ($receivesEntity->times >= 45) {
                        $this->log->info('开始', '分红次数已达上限将分红金额分到赏金中');
                        $bonusType = $this->bonusReceiveOp::BONUS_REWARD;
                        $dealUserEntity = $this->dealUserModel->where('user_id', $userOrderEntity->user_id)->find();

                        try {
                            $ret = $this->dealUserAccountOp
                                ->setBonus($bonus)
                                ->setUserEntity($dealUserEntity)
                                ->setUserCapitalModel($this->dealUserCapitalModel)
                                ->transfer();
                            $this->log->info('结束', '分红转为赏金');
                        } catch (Throwable $e) {
                            $this->log->error(exceptionLogFormat($e), '分红转为赏金时抛出异常');
                            $this->log->info('', '业务结束');
                            return true;
                        }
                    }
                    // 用户正常分红
                    else {
                        $this->log->info('开始', '满足分红条件，微信分红退款');
                        $bonusType = $this->bonusReceiveOp::BONUS_REFUND;
                        $wxConfig = WxappModel::getWxappRedis($userOrderEntity->wxapp_id);
                        $this->wxPayApi->setConfigArr($wxConfig);
                        try {
                            $ret = $this->bonusHandler
                                ->setUserOrder($userOrderEntity)
                                ->setBonusSetting($bonusSettingEntity)
                                ->setApi($this->wxPayApi)
                                ->setBonus($bonus)
                                ->run();
                            $this->log->info('结束', '微信分红退款');
                        } catch (Throwable $e) {
                            // 正常微信退款失败，根据返回的错误对本地数据进行处理
                            $dealUserEntity = $this->dealUserModel->where('user_id', $userOrderEntity->user_id)->find();
                            $wxErrorHandler = (new WxRefundErrorResponseHandle())->create($e->getMessage());
                            if($wxErrorHandler) {
                                $this->log->info('开始', '正常微信退款失败,根据错误处理本地数据');
                                $wxErrorHandler
                                    ->setBonus($bonus)
                                    ->setWxApi($this->wxPayApi)
                                    ->setRefundOrderEntity($userOrderEntity)
                                    ->setPaidUserOrderEntity($paidUserOrderEntity)
                                    ->setBonusSettingEntity($bonusSettingEntity)
                                    ->setDealUserEntity($dealUserEntity)
                                    ->setReceivesEntity($receivesEntity)
                                    ->setBonusReceiveOp($this->bonusReceiveOp)
                                    ->setBonusReceiveUserOp($this->bonusReceiveUserOp)
                                    ->setDealUserAccountOp($this->dealUserAccountOp)
                                    ->setUserModel($this->userModel)
                                    ->setUserCapitalModel($this->dealUserCapitalModel)
                                    ->setBonusReceiveUserModel($this->bonusReceiveUserModel)
                                    ->handle();
                                $this->log->info('结束', '正常微信退款失败,根据错误处理本地数据');
                                $this->log->info('', '业务结束');
                                return true;
                            } else {
                                $this->log->error(exceptionLogFormat($e), '微信分红退款时抛出异常');
                                $this->log->info('', '业务结束');
                                return true;
                            }
                        }
                        $this->log->info(bool2str($ret), '当前用户分红结束');
                    }
                    // 分红失败，
                    if (!$ret) {
                        $this->log->info('失败', '当前用户分红结果');

                        // 写入分红退款失败记录表
                        try {
                            $this->bonusRefundOp
                                ->setUserOrder($userOrderEntity)
                                ->setBonus($bonus)
                                ->setBonusSettingEntity($bonusSettingEntity)
                                ->setModel($this->bonusRefundModel)
                                ->setUserModel($this->userModel)
                                ->setWxRefundResponse(['err_code_des' => '用户分红失败，入失败表'])
                                ->create();
                        } catch (Throwable $e) {
                            $this->log->error(exceptionLogFormat($e), '分红退款失败写入失败记录表时抛出异常');
                        }
                        $this->log->info('', '业务结束');
                        return true;
                    }

                    $this->log->info('成功', '当前用户分红结果');
                }

                // 分红结束，分红余额小于等于分红金额|用户订单已达到分红结束时间， 设置订单分红已结束标记
                if ($receivesEntity->balance <= 0 || bccomp(strval($bonus), strval($receivesEntity->balance), 2) == 1 || bccomp(strval($receivesEntity->balance), strval($bonus), 2) == 0 || $receivesEntity->finish_time <= time()) {
                    $this->log->info('用户分红余额为0或用户活动时间到期，不再继续分红', '更新用户分红列表信息主表');
                    $this->log->info(bool2str($receivesEntity->balance == 0), '用户分红余额等于0');
                    $this->log->info(bool2str(bccomp(strval($bonus), strval($receivesEntity->balance), 2) == 1), '用户分红余额小于分红金额');
                    $this->log->info(bool2str(bccomp(strval($receivesEntity->balance), strval($bonus), 2) == 0), '用户分红余额等于分红金额');
                    $this->log->info(bool2str($receivesEntity->finish_time <= time()), '活动时间到期');
                    $isFinished = $this->bonusReceiveOp::FINISHED;
                } else {
                    $this->log->info('用户可以继续分红', '更新用户分红列表信息主表');
                    $isFinished = $this->bonusReceiveOp::NOT_FINISHED;
                }
                // 根据标记，更新分红主表状态
                $this->log->info('开始', '更新用户分红信息主表');
                try {
                    $this->bonusReceiveOp
                        ->setUserModel($this->userModel)
                        ->setReceiveEntity($receivesEntity)
                        ->setBonus($bonus)
                        ->update($isFinished, $bonusType);
                } catch (Throwable $e) {
                    $this->log->error(exceptionLogFormat($e), '更新用户分红列表信息主表时抛出异常');
                    $this->log->info('', '业务结束');
                    return true;
                }
                $this->log->info('结束', '更新用户分红信息主表');
                // 更新分红副表信息
                if($bonus > 0) {
                    $this->log->info('开始', '更新用户本次分红入分红记录副表');
                    try {
                        $this->bonusReceiveUserOp
                            ->setBonusSetting($bonusSettingEntity)
                            ->setRefundType($bonusType)
                            ->setOtherOrder($paidUserOrderEntity)
                            ->setRefundData($this->bonusHandler->getWxRefundData())
                            ->setBonus($bonus)
                            ->setReceiveEntity($receivesEntity)
                            ->setModel($this->bonusReceiveUserModel)
                            ->append();
                    } catch (Throwable $e) {
                        $this->log->error(exceptionLogFormat($e), '添加用户本次分红入分红记录副表时抛出异常');
                        $this->log->info('', '业务结束');
                        return true;
                    }
                }

                $this->log->info('', '业务结束');
                return true;
            } catch (Throwable $e) {
                $this->log->error(exceptionLogFormat($e), '用户分红队列消费抛出异常');
            }
            $this->log->info('', '业务结束');
            return true;
        };
//        $queueName = $this->request->server()['argv'][2];//todo 按商户mchid号，入列
        $this->rmq->run($processMessage, 'merchant', 'bonus', 'bonus');
        return true;
    }
    
    public function expire()
    {
        $sleepSecond = 5;
        $this->log->setFilename('weigudong/expire');
        $this->bonusConsumerInit();
        while(true){
            try {
            $receives = $this->bonusReceiveModel->where('type', 0)->whereTime('finish_time', '<=', time())->whereTime('finish_time', '>', 0)->select();
            if(!$receives) {
                sleep($sleepSecond);
                continue;
            }
            $receivesArr = $receives->all();
            if(empty($receivesArr)){
                sleep($sleepSecond);
                continue;
            }
            $this->log->info('', '-----------------------------------------------------------------');
            $this->log->info($receives->toArray(), '需要做过期处理的分红');
            $userIds = array_column($receives->toArray(), 'user_id');
            $userIds = array_unique($userIds);
            $wxAppIds = array_column($receives->toArray(), 'wxapp_id');
            $wxAppIds = array_unique($wxAppIds);
            $wxApps = $this->miniProgramModel->whereIn('wxapp_id', $wxAppIds)->field('wxapp_id,service_type')->select();
            $wxApps = $wxApps->toArray();
            $longDaReceives = [];
            foreach($wxApps as $wxApp) {
                if($wxApp['service_type'] == 1) {
                    $longDaReceives[] = $wxApp['wxapp_id'];
                }
            }
            $wxAppSettings = $this->bonusSettingModel->whereIn('wxapp_id', $wxAppIds)->field('wxapp_id, moneypercentstatus')->select();
            $wxAppSettings = $wxAppSettings->toArray();
            $wxAppSettings = array_column($wxAppSettings, 'moneypercentstatus', 'wxapp_id');
            $users = $this->userModel->whereIn('user_id', $userIds)->field('balance, user_id, wxapp_id')->select();
            $users = $users->all();
            $users = array_column($users, null, 'user_id');
            $bonusType = $this->bonusReceiveOp::BONUS_BALANCE;
            $this->log->info('', '本轮过期处理开始');
            foreach($receives as $receivesEntity) {
                if(!in_array($receivesEntity->wxapp_id, $longDaReceives)) {
                    continue;
                }
                $userEntity = $users[$receivesEntity->user_id];
                $this->log->info($userEntity->toArray(), '用户信息');
                $balance = $users[$receivesEntity->user_id]->balance + $receivesEntity->balance;
                $this->log->info($balance, '用户零钱更新后余额');
                $userOrderEntity = new \stdClass();
                $userOrderEntity->order_no = $receivesEntity->order_no;
                $bonus = $receivesEntity->balance;
                Db::transaction(function() use ($userEntity, $userOrderEntity, $balance, $bonus, $bonusType, $receivesEntity, $wxAppSettings){
                    //分红余额转用户零钱
                    if($wxAppSettings[$receivesEntity->wxapp_id] == 1) {
                        $this->log->info('开始', '处理分红余额转用户零钱');
                        $ret = $this->userAccountOp->setUserEntity($userEntity)->setOrderEntity($userOrderEntity)->upgradeBalance($balance,$receivesEntity->balance);
                        $this->log->info(bool2str($ret), '处理分红余额转用户零钱结果');
                        //更新分红队列副表
                        $this->log->info('开始', '更新分红队列副表');
                        $ret = $this->bonusReceiveUserOp->setRefundType($bonusType)->setBonus($bonus)->setReceiveEntity($receivesEntity)->setModel($this->bonusReceiveUserModel)->append();
                        $this->log->info(bool2str($ret), '更新分红队列副表结果');
                    } else {
                        $bonus = 0;
                    }
                    //更新分红队列主表
                    $this->log->info('开始', '更新分红队列主表');
                    $ret = $this->bonusReceiveOp->setReceiveEntity($receivesEntity)->setUserModel($this->userModel)->setBonus($bonus)->update($this->bonusReceiveOp::FINISHED, $bonusType);
                    $this->log->info(bool2str($ret), '更新分红队列主表结果');
                });
            }
            $this->log->info('', '本轮过期处理结束');
            sleep($sleepSecond);
            } catch(Throwable $t) {
                $this->log->info(exceptionLogFormat($t), '运行抛出了异常');
                sleep($sleepSecond);
            }
        }
    }


    protected function dividendConsumerInit()
    {
        $this->systemDividendHandler = new SystemDividendHandler();
        $this->agentDividendHandler  = new AgentDividendHandler();
        $this->storeDividendHandler  = new StoreDividendHandler();
        $this->bonusHandler          = new BonusHandler();
        $this->systemDividendOrderOp = new SystemDividendOrderOp();
        $this->agentDividendOrderOp  = new AgentDividendOrderOp();
        $this->storeDividendOrderOp  = new StoreDividendOrderOp();
        $this->bonusReceiveOp        = new BonusReceiveOp();
        $this->bonusReceiveUserOp    = new BonusReceiveUserOp();
        $this->bonusRefundOp         = new BonusRefundOp();
        $this->cardOrderHandler      = new VipCardHandler();
        $this->userOrderModel        = new Order();
        $this->userModel             = new User();
        $this->bonusSettingModel     = new Wxsetting();
        $this->divideAgentModel      = new Service();
        $this->divideSystemModel     = new System();
        $this->divideStoreModel      = new Store();
        $this->miniProgramModel      = new WxappModel();

        $this->agentModel            = new Agent();
        $this->bonusReceiveModel     = new Receive();
        $this->bonusReceiveUserModel = new ReceiveUser();
        $this->bonusRefundModel      = new Refund();
        $this->cardOrderModel        = new VipCardOrder();
        if(Env::get('mock.pay')) {
            $this->wxPayApi          = MockWeChatPay::instance();
            $this->dividendBonusApi  = MockWeChatProfitSharing::instance();
        } else {
            $this->wxPayApi          = new WxPay();
            $this->dividendBonusApi  = new Abonus();
        }
        $this->userOrderOp           = new UserOrderOp();

    }

    protected function bonusConsumerInit()
    {

        $this->userOrderModel        = new Order();
        $this->bonusReceiveModel     = new Receive();
        $this->dealUserAccountOp     = new DealUserAccountOp();
        $this->userAccountOp         = new UserAccountOp();
        $this->userModel             = new User();
        $this->dealUserCapitalModel  = new Capital();
        $this->bonusHandler          = new BonusHandler();
        $this->bonusRefundModel      = new Refund();
        $this->bonusRefundOp         = new BonusRefundOp();
        $this->bonusSettingModel     = new Wxsetting();
        $this->dealUserModel         = new DealUser();
        $this->storeDividendOrderOp  = new StoreDividendOrderOp();
        $this->divideStoreModel      = new Store();
        if(Env::get('mock.pay')) {
            $this->wxPayApi = MockWeChatPay::instance();
        }else{
            $this->wxPayApi              = new WxPay();
        }
        $this->bonusReceiveUserOp    = new BonusReceiveUserOp();
        $this->bonusReceiveOp        = new BonusReceiveOp();
        $this->bonusReceiveUserModel = new ReceiveUser();
        $this->miniProgramModel      = new WxappModel();

    }
}